package cn.com.yang.algorithm.v4;

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
 
import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Arrays;
/**
 * 
 * @author yangyijin
 * @Date 2022.07.06
 */
public class SM3Util {

    private static final String ENCODING = "UTF-8";
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
 
    /**
     * sm3算法加密
     * @explain
     * @param paramStr 待加密字符串
     * @return 返回加密后，固定长度=32的16进制字符串
     */
    public static String encrypt(String paramStr){
        // 将返回的hash值转换成16进制字符串
        String resultHexString = "";
        try {
            // 将字符串转换成byte数组
            byte[] srcData = paramStr.getBytes(ENCODING);
            // 调用hash()
            byte[] resultHash = hash(srcData);
            // 将返回的hash值转换成16进制字符串
            resultHexString = ByteUtils.toHexString(resultHash);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return resultHexString;
    }
 
    /**
     * 返回长度=32的byte数组
     * @explain 生成对应的hash值
     * @param srcData
     * @return
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }
    /**
     * sm3算法加密
     * @explain
     * @param paramStr 待加密字符串
     * @param key 密钥
     * @return 返回加密后，固定长度=32的16进制字符串
     */
    public static String encryptPlus(String paramStr,String key){
        // 将返回的hash值转换成16进制字符串
        String resultHexString = "";
        try {
            // 将字符串转换成byte数组
            byte[] srcData = paramStr.getBytes(ENCODING);
            // 调用hash()
            byte[] resultHash = hmac(srcData,key.getBytes(ENCODING));
            // 将返回的hash值转换成16进制字符串
            resultHexString = ByteUtils.toHexString(resultHash);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return resultHexString;
    }
 
    /**
     * 通过密钥进行加密
     * @explain 指定密钥进行加密
     * @param key 密钥
     * @param srcData 被加密的byte数组
     * @return
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        mac.update(srcData, 0, srcData.length);
        byte[] result = new byte[mac.getMacSize()];
        mac.doFinal(result, 0);
        return result;
    }
 
    /**
     * 判断源数据与加密数据是否一致
     * @explain 通过验证原数组和生成的hash数组是否为同一数组，验证2者是否为同一数据
     * @param srcStr 原字符串
     * @param sm3HexString 16进制字符串
     * @return 校验结果
     */
    public static boolean verify(String srcStr, String sm3HexString) {
        boolean flag = false;
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
            byte[] newHash = hash(srcData);
            if (Arrays.equals(newHash, sm3Hash)){
                flag = true;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return flag;
    }
    /**
     	* 盐值比较
     * @param srcStr
     * @param key
     * @param sm3HexString
     * @return
     */
    public static boolean verifySalt(String srcStr, String key, String sm3HexString) {
        boolean flag = false;
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
            byte[] resultHash = hmac(srcData,key.getBytes(ENCODING));
            if (Arrays.equals(resultHash, sm3Hash)){
                flag = true;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return flag;
    }
 
    public static void main(String[] args) {
        String str =  "[{OrgId=0102, AddrDtl=中华北大街370北郡A区底商河北银行北郡支行, Phone=13073125275, TotalPrice=806.6, OrgName=石家庄分行北郡支行, Buyer=杨平, RcvAddr=[Ljava.lang.String;@77c96a80, "
        		+ "		OrderInfo=[{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240}, "
        		+ "{Price=4.4, ProdName=小宝贝3连包抽取式面巾纸, Num=64, ProdId=P2022030900007241},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240},"
        		+ "{Price=12.5, ProdName=小宝贝海洋铂金装5层10卷无芯卫生纸, Num=42, ProdId=P2022030900007240}], OrderId=D20220614151243222850000000020}]";;
        //秘钥
        String key = "privatekey";
        String sm3hex = SM3Util.encryptPlus(str,key);
        System.out.println("参数:" + str);
        System.out.println("密文:" + sm3hex);
        System.out.println(SM3Util.verifySalt(str,key,sm3hex));
    }


}
